package fr.uniscol;

import fr.uniscol.model.DefaultUser;
import fr.uniscol.model.IUniscolUser;
import fr.uniscol.model.ImportedDataModel;
import fr.uniscol.model.RapportTraitement;
import fr.uniscol.model.RapportTraitementImportSTS;
import fr.uniscol.mvc.SessionExpireeException;
import fr.uniscol.service.IClasseService;
import fr.uniscol.service.IGroupeService;
import fr.uniscol.service.IImportDonneesService;
import fr.uniscol.service.IReferenceMatieresService;
import fr.uniscol.siecle.model.FichierSIECLE;
import fr.uniscol.siecle.parsers.IFichierSIECLEParser;
import fr.uniscol.siecle.parsers.ParsingResults;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

@SessionAttributes(value = {"importedDatasModel", "rapportTraitement"})
public class ImportDonneesController extends UniscolMainController {

	public static Logger log = Logger.getLogger(ImportDonneesController.class);

	@Autowired
	private IImportDonneesService importsDonneesService;
    
    @Autowired
    private IClasseService classeService;
    
    @Autowired
    private IGroupeService groupeService;
    
    @Autowired
    private IReferenceMatieresService matiereService;
	
	private Map<String, IFichierSIECLEParser> parsers = null;
	
	public Map<String, IFichierSIECLEParser> getParsers() {
		return parsers;
	}

	public void setParsers(Map<String, IFichierSIECLEParser> parsers) {
		this.parsers = parsers;
	}

	public IImportDonneesService getImportsDonneesService() {
		return importsDonneesService;
	}

	public void setImportsDonneesService(IImportDonneesService importsDonneesService) {
		this.importsDonneesService = importsDonneesService;
	}
    
    @ModelAttribute("rapportTraitement")
    public RapportTraitement getRapportTraitementImportation(Model model){
        if(model.asMap().containsKey("rapportTraitement")){
            return (RapportTraitement) model.asMap().get("rapportTraitement");
        }
        
        RapportTraitement rapport = new RapportTraitementImportSTS();
        rapport.setDoublons(false);
        
        return rapport;
    }

	@RequestMapping(value="/imports", method=RequestMethod.GET)
	public String showFormImports(){
		
		return "imports";
	}
	
	private static String createDestinationDir(IUniscolUser utilisateur, String name) {
		
		String dir = "/uniscol/files/" + utilisateur.getEtablissement().getUai() + "/imports/";
		
		DateFormat df = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
		dir += df.format(new Date()) + "/";
		
		new File(dir).mkdirs();
		
		return dir + name.toLowerCase();
	}
	
	@RequestMapping(value="/imports", method=RequestMethod.POST)
	/*public String importDonnees(@RequestParam(value="communs", required=false) MultipartFile fCommuns, 
								@RequestParam(value="nomenclatures", required=false) MultipartFile fNomenclatures,
								@RequestParam(value="structures", required=false) MultipartFile fStructures,
								@RequestParam(value="eleves", required=false) MultipartFile fEleves){*/
	public String importDonnees(HttpServletRequest request, Model model, HttpSession session){
		
		MultipartHttpServletRequest multiPartRequest = (MultipartHttpServletRequest) request;
		
		ImportedDataModel importedDatas = new ImportedDataModel();
		importedDatas.setBase(getUtilisateur(session).getBaseSelectionnee());
		
		/*Iterator<String> names= multiPartRequest.getFileNames();
		while(names.hasNext()){
			log.info("File: " + names.next());
		}*/
		
		MultipartFile mFile = null;
		Map<String, MultipartFile> fileMap = multiPartRequest.getFileMap();
		Iterator<String> itn = multiPartRequest.getFileNames();
		String name = null;
		File destination = null;
		
		while(itn.hasNext()){
			name = itn.next();
			
			mFile = multiPartRequest.getFile(name);
			
			if(name.equals("") || mFile.getOriginalFilename().equals("")){
				continue;
			}
			
			destination = new File(createDestinationDir(getUtilisateur(session), mFile.getOriginalFilename()));
			
			try{
				mFile.transferTo(destination);
				log.info("UPLOAD: " + mFile.getOriginalFilename()  + " >> " + destination.getAbsolutePath());
				
				importedDatas.getFichiers().put(name, destination);
				
			} catch (IllegalStateException e) {
				log.error("UPLOAD FAILED: " + mFile.getOriginalFilename()  + " >> " + destination.getAbsolutePath() + " : " + e.getMessage());
				e.printStackTrace();
				
			} catch (IOException e) {
				log.error("UPLOAD FAILED: " + mFile.getOriginalFilename()  + " >> " + destination.getAbsolutePath() + " : " + e.getMessage());
				e.printStackTrace();
			}
		}
		
		model.addAttribute("importedDatasModel", importedDatas);
		
		return "importing";
	}
	
	@RequestMapping("/savefiles")
	@ResponseBody
	public String savesFiles(@ModelAttribute("importedDatasModel") ImportedDataModel importedDatasModel, Model model, HttpSession session){
		
		// Parsing
		Iterator<String> itn = importedDatasModel.getFichiers().keySet().iterator();
		String name = null;
		File fichier = null;
		ParsingResults parsingResults = new ParsingResults();
		FichierSIECLE donneesParsees = null;
		
		while(itn.hasNext()){
			name = itn.next();
		
			fichier = importedDatasModel.getFichiers().get(name);
			try{
				donneesParsees = getParsers().get(name).parseFichier(fichier, parsingResults);
				importedDatasModel.getDonnees().put(name, donneesParsees);
				
			}catch(ParseException pe){
				log.error("PARSE: Echec de la lecture du fichier: " + name);
				log.error(pe);
				pe.printStackTrace();
			}
		}
		
        RapportTraitement rapport = getRapportTraitementImportation(model);
        
		String ret = "";
		if(importsDonneesService.saveDonnees(getUtilisateur(session).getEtablissement(), importedDatasModel, rapport)){
			ret = "OK";
			alertSuccess("imports.ok", "Les donnés ont été importées avec succès", model);
		}else{
			ret = "NOK";
			alertError("imports.error", "Les données n'ont pas été importées", model);
		}
		
		return ret;
	}
    
    @RequestMapping("/imports.retry")
    public String retry(@ModelAttribute("importedDatasModel") ImportedDataModel importedDatasModel){
        return "";
    }
	
	@RequestMapping("/imports.finish")
	public String importsTermines(SessionStatus sessionStatus, Model model, HttpSession session){
        
        RapportTraitementImportSTS rapportTraitement = (RapportTraitementImportSTS) getRapportTraitementImportation(model);
        
        IUniscolUser user = getUtilisateur(session);
        
        if(!rapportTraitement.getCorrespondances().isEmpty()){
            
            model.addAttribute("divisions", classeService.getAllClassesOfEtablissement(user.getBaseSelectionnee()));
            model.addAttribute("groupes", groupeService.getAllGroupesOfEtablissement(user.getBaseSelectionnee()));
            model.addAttribute("matieres", matiereService.findAllMatieres(user.getBaseSelectionnee()));
            
            return "imports_correspondances";
        }else{
            sessionStatus.setComplete();
            return "imports_termines";
        }
	}
}
